using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WorkflowActions;

namespace DP.Sharepoint.Workflow
{
    [ActivityValidator(typeof (CopyListItemActivityValidator))]
    public partial class CopyListItemExtended : Activity
    {
        public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context",
                                                                                         typeof (WorkflowContext),
                                                                                         typeof (CopyListItemExtended));

        public static DependencyProperty DestinationListUrlProperty = DependencyProperty.Register("DestinationListUrl",
                                                                                                  typeof (string),
                                                                                                  typeof (
                                                                                                      CopyListItemExtended
                                                                                                      ));


        public static DependencyProperty ListIdProperty = DependencyProperty.Register("ListId", typeof (string),
                                                                                      typeof (CopyListItemExtended));


        public static DependencyProperty ListItemProperty = DependencyProperty.Register("ListItem", typeof (int),
                                                                                        typeof (CopyListItemExtended));


        public static DependencyProperty MoveProperty = DependencyProperty.Register("Move", typeof (string),
                                                                                    typeof (CopyListItemExtended));

        public static DependencyProperty OutListItemIDProperty = DependencyProperty.Register("OutListItemID",
                                                                                             typeof (int),
                                                                                             typeof (
                                                                                                 CopyListItemExtended));


        public static DependencyProperty OverwriteProperty = DependencyProperty.Register("Overwrite", typeof (string),
                                                                                         typeof (CopyListItemExtended));

        public CopyListItemExtended()
        {
            InitializeComponent();
        }

        [Description("Context")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public WorkflowContext __Context
        {
            get { return ((WorkflowContext) (base.GetValue(__ContextProperty))); }
            set { base.SetValue(__ContextProperty, value); }
        }

        [Description("ListId")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string ListId
        {
            get { return ((string) (base.GetValue(ListIdProperty))); }
            set { base.SetValue(ListIdProperty, value); }
        }

        [Description("ListItem")]
        [ValidationOption(ValidationOption.Required)]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int ListItem
        {
            get { return ((int) (base.GetValue(ListItemProperty))); }
            set { base.SetValue(ListItemProperty, value); }
        }

        [Description("Specifies whether to move an item or simply copy it")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        public string Move
        {
            get { return ((string) (base.GetValue(MoveProperty))); }
            set { base.SetValue(MoveProperty, value); }
        }

        [Description("This is the description which appears in the Property Browser")]
        [Category("This is the category which will be displayed in the Property Browser")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        public string Overwrite
        {
            get { return ((string) (base.GetValue(OverwriteProperty))); }
            set { base.SetValue(OverwriteProperty, value); }
        }

        [Description("Destination list url")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Required)]
        public string DestinationListUrl
        {
            get { return ((string) (base.GetValue(DestinationListUrlProperty))); }
            set { base.SetValue(DestinationListUrlProperty, value); }
        }


        [Description("This is the description which appears in the Property Browser")]
        [Category("This is the category which will be displayed in the Property Browser")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int OutListItemID
        {
            get { return ((int) (base.GetValue(OutListItemIDProperty))); }
            set { base.SetValue(OutListItemIDProperty, value); }
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            using (
                WorkflowHistoryTraceListener myTracer = new WorkflowHistoryTraceListener(executionContext,
                                                                                         WorkflowInstanceId))
            {
                Trace.Listeners.Add(myTracer);

                try
                {
                    //elevate privilages, because SHAREPOINT\System account has full access privilages to the entire farm
                    SPSecurity.RunWithElevatedPrivileges(delegate
                                                             {
                                                                 using (
                                                                     SPSite sourceSite =
                                                                         new SPSite(__Context.Web.Site.ID))
                                                                 {
                                                                     using (
                                                                         SPWeb sourceWeb =
                                                                             sourceSite.AllWebs[__Context.Web.ID])
                                                                     {
                                                                         //replace any workflow variables
                                                                         string destinationUrlProcessed =
                                                                             Common.ProcessStringField(
                                                                                 executionContext, DestinationListUrl);

                                                                         using (
                                                                             SPSite destSite =
                                                                                 new SPSite(destinationUrlProcessed))
                                                                         {
                                                                             using (SPWeb destWeb = destSite.OpenWeb())
                                                                             {
                                                                                 SPList destinationList = null;

                                                                                 //each list, even a non document library list has at least a root folder.
                                                                                 SPFolder destFolder =
                                                                                     destWeb.GetFolder(
                                                                                         destinationUrlProcessed);

                                                                                 if (!destFolder.Exists)
                                                                                     throw new InvalidOperationException
                                                                                         (string.Format(
                                                                                              "List at {0} does not exist!",
                                                                                              DestinationListUrl));

                                                                                 destinationList =
                                                                                     destWeb.Lists[
                                                                                         destFolder.ParentListId];


                                                                                 SPList sourceList =
                                                                                     sourceWeb.Lists[new Guid(ListId)];

                                                                                 SPListItem sourceItem =
                                                                                     sourceList.Items.GetItemById(
                                                                                         ListItem);

                                                                                 ListItemCopier.ListItemCopyOptions
                                                                                     options =
                                                                                         new ListItemCopier.
                                                                                             ListItemCopyOptions();

                                                                                 options.IncludeAttachments = true;

                                                                                 options.OperationType = bool.Parse(Move)
                                                                                                             ? ListItemCopier
                                                                                                                   .
                                                                                                                   OperationType
                                                                                                                   .Move
                                                                                                             : ListItemCopier
                                                                                                                   .
                                                                                                                   OperationType
                                                                                                                   .Copy;

                                                                                 options.Overwrite =
                                                                                     bool.Parse(Overwrite);

                                                                                 options.DestinationFolder = destFolder;

                                                                                 using (
                                                                                     ListItemCopier myCopier =
                                                                                         new ListItemCopier(sourceItem,
                                                                                                            destinationList,
                                                                                                            options))
                                                                                 {
                                                                                     OutListItemID = myCopier.Copy();
                                                                                 }
                                                                             }
                                                                         }
                                                                     }
                                                                 }
                                                             });
                }
                catch (Exception e)
                {
                    Common.LogExceptionToWorkflowHistory(e, executionContext, WorkflowInstanceId);

                    throw Common.WrapWithFriedlyException(e, "Error while copying list items.");
                }
                finally
                {
                    Trace.Listeners.Remove(myTracer);                    
                }
            }

            return base.Execute(executionContext);
        }
    }
}